// standard libraries
#include <vector>

// custom libraries
#include "..\include\audio\sound.h"
#include "..\include\audio\sound_renderer.h"

#include "..\include\game_state\game_state.h"
#include "..\include\game_state\end_state.h"

#include "..\include\graphics\graphics_renderer.h"

#include "..\include\resource_manager.h"
#include "..\include\user_controller.h"
#include "..\include\game_manager.h" // matching header


// ==================================
//    CONSTRUCTORS and DESTRUCTORS
// ==================================

GameManager::GameManager()
{
	graphicsRenderer_ = new GraphicsRenderer;
	userController_ = new UserController;
}

GameManager::~GameManager()
{
	if (!stateStack_.empty()) {
		stateStack_.back()->onExit();
		for (int i = stateStack_.size() - 1; i >= 0; i--)
			stateStack_[i]->onClose();
	}

	delete graphicsRenderer_;
	delete userController_;
}


// ==================================
//         UPDATE and RENDER
// ==================================

void GameManager::update()
{
	if (!stateStack_.empty())
		// Update the top state and grant it acces to the user controller and
		// the game manager in order to be able to change states.
		stateStack_.back()->update(this, userController_);
}

void GameManager::render()
{
	if (!stateStack_.empty())
		// Draw the top state and grant it acces to the renderer.
		stateStack_.back()->render(graphicsRenderer_);
}


// ==================================
//         STATE MANAGEMENT
// ==================================

void GameManager::setStartState(GameState* gameState)
{
	changeState(gameState);
}

void GameManager::changeState(GameState* gameState)
{
	if (!stateStack_.empty()) {
		stateStack_.back()->onExit();

		for (int i = stateStack_.size() - 1; i >= 0; i--)
			stateStack_[i]->onClose();

		stateStack_.clear();
	}

	stateStack_.push_back(gameState);
	stateStack_.back()->onOpen();
	stateStack_.back()->onEnter();
}

void GameManager::pushState(GameState* gameState)
{
	if (!stateStack_.empty())
		stateStack_.back()->onExit();

	stateStack_.push_back(gameState);
	stateStack_.back()->onOpen();
	stateStack_.back()->onEnter();
}

void GameManager::popState()
{
	if (!stateStack_.empty()) {
		stateStack_.back()->onExit();
		stateStack_.back()->onClose();
		stateStack_.pop_back();
		if (!stateStack_.empty())
			stateStack_.back()->onEnter();
	}
}


// ==================================
//              OTHERS
// ==================================

bool GameManager::isRunning()
{
	return ((!stateStack_.empty()) && 
		    (stateStack_.back() != EndState::Instance()));
}
